#define __LIBRARY__
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <stdlib.h>

#define BUFFER_LEN 10
#define CACHE_FILE "cache.txt"

_syscall2(sem_t*, sem_open, const char*, name, unsigned int, value)
_syscall1(int, sem_wait, sem_t*, sem)
_syscall1(int, sem_post, sem_t*, sem)
_syscall1(int, sem_unlink, const char *, name)


void remove_special_line(const char *filename, int line, char *result);

int main(int argc, char const *argv[])
{
    int i;
    FILE *fp;
    char buffer[255];
    int pid1;
    int pid2;
    // 信号量
    sem_t *empty = sem_open("/empty", BUFFER_LEN);

    sem_t *full = sem_open("/full", 0);

    sem_t *mutex = sem_open("/mutex", 1);

    // 生产者
    if (!fork())
    {
        // 清空文件内容
        fp = fopen(CACHE_FILE, "w");
        fclose(fp);

        for (i = 0; i < 500; i++)
        {
            sem_wait(empty);
            sem_wait(mutex);

            fp = fopen(CACHE_FILE, "a");
            fprintf(fp, "%d\n", i);
            printf("produce %d\n", i);
            fflush(stdout);
            fclose(fp);

            sem_post(mutex);
            sem_post(full);
        }
    }
    else
    {
        pid1 = fork();
        // 消费者1
        if (!pid1)
        {
            printf("custmer 1 join\n");
            while (1)
            {
                // printf("customer 1 wait full\n");
                fflush(stdout);
                sem_wait(full);
                // printf("customer 1 get full\n");
                // printf("customer 1 wait mutex\n");
                fflush(stdout);
                sem_wait(mutex);
                // printf("customer 1 get mutex\n");/
                fflush(stdout);

                remove_special_line(CACHE_FILE, 1, buffer);
                printf("%d: %s\n", 1, buffer);
                fflush(stdout);

                sem_post(mutex);
                // printf("customer 1 post mutex\n");
                sem_post(empty);
                // printf("customer 1 post empty\n");
            }
        }
        else
        {
            printf("create custmer[%d] \n", pid1);
            // 消费者2
            pid2 = fork();
            if (!pid2)
            {
                printf("custmer 2 join\n");
                while (1)
                {
                    // printf("customer 2 wait full\n");
                    fflush(stdout);
                    sem_wait(full);
                    // printf("customer 2 get full\n");
                    // printf("customer 2 wait mutex\n");
                    fflush(stdout);
                    sem_wait(mutex);
                    // printf("customer 2 get mutex\n");
                    fflush(stdout);

                    remove_special_line(CACHE_FILE, 1, buffer);
                    printf("%d: %s\n", 2, buffer);
                    fflush(stdout);

                    sem_post(mutex);
                    // printf("customer 2 post mutex\n");
                    sem_post(empty);
                    // printf("customer 2 post empty\n");
                }
            }
            else
            {
                printf("create custmer[%d] \n", pid2);
            }
        }
    }

    wait(NULL);
    sem_close(empty);
    sem_close(full);
    sem_close(mutex);
    sem_unlink("/empty");
    sem_unlink("/full");
    sem_unlink("/mutex");

    return 0;
}

void remove_special_line(const char *filename, int line, char *result)
{
    FILE *tmp;
    FILE *fp;
    char buffer[255];
    int i;
    int len = 0;

    tmp = fopen("tmp.txt", "w");
    fp = fopen(filename, "r");
    if (!fp)
    {
        printf("file %s not found\n", filename);
        return;
    }

    // 写入临时文件
    while (fgets(buffer, 255, fp))
    {
        len++;
        fputs(buffer, tmp);
    }
    fflush(tmp);
    fclose(tmp);
    fclose(fp);

    // 重新拷贝回来
    tmp = fopen("tmp.txt", "r");
    fp = fopen(filename, "w");

    for (i = 0; i < len; i++)
    {
        if (i + 1 == line)
        {
            fgets(result, 255, tmp);
        }
        else
        {
            fgets(buffer, 255, tmp);
            fputs(buffer, fp);
        }
    }
    fflush(fp);
    fclose(tmp);
    fclose(fp);
    fflush(stdout);
}
